home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / unexhp9k3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-25  |  13.1 KB  |  479 lines

  1. /*
  2.  * Code to do an unexec for HPUX 8.0 on an HP9000/[34]00 for a
  3.  * dynamically linked temacs.
  4.  
  5.    Copyright (C) 1992-1993 Free Software Foundation, Inc.
  6.  
  7. This file is part of XEmacs.
  8.  
  9. XEmacs is free software; you can redistribute it and/or modify it
  10. under the terms of the GNU General Public License as published by the
  11. Free Software Foundation; either version 2, or (at your option) any
  12. later version.
  13.  
  14. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  15. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17. for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with XEmacs; see the file COPYING.  If not, write to the Free
  21. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  22.  
  23. /* Synched up with: Not in FSF. */
  24.  
  25. /*
  26. Created 29-Oct-92 by Harlan Sexton for SunOS
  27.  
  28. Modified Jan 93 by Hamish Macdonald for HPUX
  29.  */
  30.  
  31. /********************** Included .h Files **************************/
  32.  
  33. #include <config.h>
  34.  
  35. #include <stdarg.h>
  36. #include <sys/param.h>
  37. #include <sys/file.h>
  38. #include <sys/stat.h>
  39. #include <sys/types.h>
  40. #include <string.h>
  41. #include <stdio.h>
  42. #include <signal.h>
  43. #include <a.out.h>
  44. #include <unistd.h>
  45. #include <ctype.h>
  46. #include <sys/dir.h>
  47.  
  48. #include "sysdep.h"
  49.  
  50. /* XEmacs: Richard Cognot <cognot@ensg.u-nancy.fr> says we need these */
  51. extern void perror(const char*);
  52. extern int sys_nerr;
  53. extern char *sys_errlist[];
  54. extern char *strerror (int);
  55.  
  56.  
  57. /********************** Macros *************************************/
  58.  
  59. #define SYS_ERR \
  60.  ((errno > 0)?((errno < sys_nerr)?(sys_errlist[errno]):\
  61.                "unknown system error"): "unknown error")
  62.  
  63. #define MASK_UP(x,p_of_two) \
  64.  ((((unsigned long) (x)) + ((p_of_two) - 1)) & (~((p_of_two) - 1)))
  65.  
  66. #define MASK_DOWN(x,p_of_two) (((unsigned long) (x)) & (~((p_of_two) - 1)))
  67.  
  68. /********************** Function Prototypes/Declarations ***********/
  69.  
  70. static void unexec_error (const char *fmt, int use_errno, ...);
  71. static int unexec_open (char *filename, int flag, int mode);
  72. static long unexec_seek (int fd, long position);
  73. static void unexec_read (int fd, long position, char *buf, int bytes);
  74. static void unexec_write (int fd, long position, char *buf, int bytes);
  75. static void unexec_copy (int new_fd, int old_fd, long old_pos, long new_pos,
  76.                          int bytes);
  77. static void unexec_pad (int fd, int bytes);
  78. static void unexec_fstat (int fd, struct stat *statptr);
  79. static void unexec_fchmod (int fd, int mode);
  80. int run_time_remap (char *dummy);
  81.  
  82. /********************** Variables **********************************/
  83.  
  84. /* for reporting error messages from system calls */
  85. extern int sys_nerr;
  86. extern int errno;
  87. extern int _DYNAMIC;
  88. extern char **environ;             
  89.  
  90. static unsigned long sbrk_of_0_at_unexec;
  91.              
  92. /*******************************************************************/
  93.  
  94. static void
  95. unexec_error (const char *fmt, int use_errno, ...)
  96. {
  97.   const char *err_msg = SYS_ERR;
  98.   va_list args;
  99.  
  100.   fprintf (stderr, "unexec - ");
  101.   va_start (args, use_errno);
  102.   vfprintf (stderr, fmt, args);
  103.   va_end (args);
  104.  
  105.   if (use_errno)
  106.       fprintf (stderr, ": %s", err_msg);
  107.   fprintf (stderr, "\n");
  108.   exit (1);
  109.   return;
  110. }
  111.  
  112. static int
  113. unexec_open (char *filename, int flag, int mode)
  114. {
  115.   int fd;
  116.  
  117.   errno = 0;
  118.  
  119.   fd = open (filename, flag, mode);
  120.  
  121.   if (fd < 0)
  122.     {
  123.       unexec_error ("Failure opening file %s", 1, (void *) filename, 0, 0);
  124.       return -1;
  125.     }
  126.   else
  127.     return fd;
  128. }
  129.  
  130. static long
  131. unexec_seek (int fd, long position)
  132. {
  133.   long seek_value;
  134.  
  135.   if (fd <= 0)
  136.     unexec_error ("No file open in which to seek", 0, 0, 0, 0);
  137.  
  138.   errno = 0;
  139.  
  140.   if (position < 0)
  141.     seek_value = (long) lseek (fd, 0, L_INCR);
  142.   else
  143.     seek_value = (long) lseek (fd, position, L_SET);
  144.  
  145.   if (seek_value < 0)
  146.     unexec_error ("Failed to do a seek to 0x%x in %s", 1,
  147.                   (char *) position, "unexec() output file", 0);
  148.  
  149.   return seek_value;
  150. }
  151.  
  152. static void
  153. unexec_read (int fd, long position, char *buf, int bytes)
  154. {
  155.   int n_read;
  156.   int remains = bytes;
  157.   position = unexec_seek (fd, position);
  158.  
  159.   if (bytes < 0)
  160.     unexec_error ("Attempted read of %d bytes", 0, (char *) bytes, 0, 0);
  161.  
  162.   errno = 0;
  163.  
  164.   while (remains > 0)
  165.     {
  166.       n_read = read (fd, buf, remains);
  167.       if (n_read <= 0)
  168.         unexec_error ("Read failed for 0x%x bytes at offset 0x%x in %s",
  169.                       1, (char *) bytes, (char *) position,
  170.                       "unexec() output file");
  171.       buf += n_read;
  172.       remains -= n_read;
  173.     }
  174.  
  175.   return;
  176. }
  177.  
  178. static void
  179. unexec_write (int fd, long position, char *buf, int bytes)
  180. {
  181.   int n_written;
  182.   int remains = bytes;
  183.   position = unexec_seek (fd, position);
  184.  
  185.   if (bytes < 0)
  186.     unexec_error ("Attempted write of %d bytes in %s",
  187.                   0, (char *) bytes, "unexec() output file", 0);
  188.  
  189.   errno = 0;
  190.  
  191.   while (remains > 0)
  192.     {
  193.       n_written = write (fd, buf, remains);
  194.       if (n_written <= 0)
  195.         unexec_error ("Write failed for 0x%x bytes at offset 0x%x in %s",
  196.                       1, (char *) bytes, (char *) position,
  197.                       "unexec() output file");
  198.       buf += n_written;
  199.       remains -= n_written;
  200.     }
  201.  
  202.   return;
  203. }
  204.  
  205. static void
  206. unexec_copy (int new_fd, int old_fd, long old_pos, long new_pos, int bytes)
  207. {
  208.     int remains = bytes;        
  209.     char buf[128];
  210.  
  211.     while (remains > 0)
  212.       {
  213.           int n_to_copy = remains > sizeof(buf) ? sizeof(buf) : remains;
  214.  
  215.           unexec_read (old_fd, old_pos, buf, n_to_copy);
  216.           unexec_write (new_fd, new_pos, buf, n_to_copy);
  217.  
  218.           old_pos += n_to_copy;
  219.           new_pos += n_to_copy;
  220.           remains -= n_to_copy;
  221.       }
  222.  
  223.     return;
  224. }
  225.  
  226. static void 
  227. unexec_pad (int fd, int bytes)
  228. {
  229.   if (bytes > 0)
  230.     {
  231.       char buf[1024];
  232.       int remaining = bytes;
  233.  
  234.       bzero (buf, sizeof(buf));
  235.   
  236.       while (remaining > 0)
  237.         {
  238.           int this_write = (remaining > sizeof(buf))?sizeof(buf):remaining;
  239.           unexec_write (fd, -1, buf, this_write);
  240.           remaining -= this_write;
  241.         }
  242.     }
  243. }
  244.  
  245. static void
  246. unexec_fstat (int fd, struct stat *statptr)
  247. {
  248.   errno = 0;
  249.   if (-1 == fstat (fd, statptr))
  250.     unexec_error ("fstat() failed for descriptor %d", 1, (char *) fd, 0, 0);
  251.   return;
  252. }
  253.  
  254. static void
  255. unexec_fchmod (int fd, int mode)
  256. {
  257.   errno = 0;
  258.   if (-1 == fchmod (fd, mode))
  259.     unexec_error ("fchmod() failed for descriptor %d", 1, (char *) fd, 0, 0);
  260.   return;
  261. }
  262.  
  263. /*
  264.  * EXPORTED FUNCTIONS 
  265.  */
  266.  
  267. /* this has to be a global variable to prevent the optimizers from
  268.  * assuming that it can not be 0.  
  269. */
  270. static void *dynamic_addr = (void *) &_DYNAMIC;
  271.  
  272. int
  273. unexec (char *new_name, char *old_name,
  274.         unsigned int emacs_edata, unsigned int dummy1, unsigned int dummy2)
  275. {
  276.   /* /dld.sl data */
  277.   struct dynamic *ld = 0;
  278.   /* old and new state */
  279.   int old_fd;
  280.   int new_fd;
  281.   struct exec old_hdr;
  282.   struct exec new_hdr;
  283.   struct stat old_buf;
  284.   /* some process specific "constants" */
  285.   unsigned long n_pagsiz;
  286.   caddr_t dynamic_beg;
  287.   caddr_t current_break = (caddr_t) sbrk (0);
  288.  
  289.   /* dynamically linked image? -- if so, find dld.sl structures */
  290.   if (dynamic_addr)
  291.     {
  292.       ld = (struct dynamic *) dynamic_addr;
  293. #ifdef DEBUG
  294.       printf ("dl_text = %#x\n", ld->text);
  295.       printf ("dl_data = %#x\n", ld->data);
  296.       printf ("dl_bss = %#x\n", ld->bss);
  297.       printf ("dl_end = %#x\n", ld->end);
  298.       printf ("dl_dmodule = %#x\n", ld->dmodule);
  299.       printf ("dl_dlt = %#x\n", ld->dlt);
  300.       printf ("dl_plt = %#x\n", ld->plt);
  301. #endif
  302.     }
  303.  
  304.   /* open the old and new files, figuring out how big the old one is
  305.      so that we can map it in */
  306.   old_fd = unexec_open (old_name, O_RDONLY, 0);
  307.   new_fd = unexec_open (new_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
  308.  
  309.   /* setup the header and the statbuf for old_fd */
  310.   unexec_read (old_fd, 0, (char *) &old_hdr, sizeof (old_hdr));
  311.   unexec_fstat (old_fd, &old_buf);
  312.  
  313.   /* set up some important constants */
  314.   n_pagsiz = EXEC_PAGESIZE;
  315.  
  316.   /* setup beginning of data to copy from executable */
  317.   if (ld)
  318.       dynamic_beg = ld->dmodule;
  319.   else
  320.       dynamic_beg = (caddr_t)EXEC_ALIGN (old_hdr.a_text) + old_hdr.a_data;
  321.  
  322.   /* set up the new exec */
  323.   new_hdr = old_hdr;
  324.   new_hdr.a_text = MASK_DOWN (emacs_edata, n_pagsiz);
  325.   new_hdr.a_data = MASK_UP (current_break, n_pagsiz)
  326.       - EXEC_ALIGN(new_hdr.a_text);
  327.   new_hdr.a_bss  = 0;
  328.  
  329. #ifdef DEBUG
  330.   printf ("old text %#x\n", old_hdr.a_text);
  331.   printf ("new text %#x\n", new_hdr.a_text);
  332.   printf ("old data %#x\n", old_hdr.a_data);
  333.   printf ("new data %#x\n", new_hdr.a_data);
  334.   printf ("old bss %#x\n", old_hdr.a_bss);
  335.   printf ("new bss %#x\n", new_hdr.a_bss);
  336. #endif
  337.  
  338.   /* set up this variable, in case we want to reset "the break" 
  339.      when restarting */
  340.   sbrk_of_0_at_unexec = ((unsigned long) MASK_UP (current_break, n_pagsiz));
  341.      
  342.   /* Write out the first approximation to the new file. The sizes of
  343.      each section will be correct, but there will be a number of 
  344.      corrections that will need to be made. */
  345.   {
  346.     long old_datoff = DATA_OFFSET (old_hdr);
  347.     long new_datoff = DATA_OFFSET (new_hdr);
  348.     long old_dataddr = EXEC_ALIGN (old_hdr.a_text);
  349.     long new_dataddr = EXEC_ALIGN (new_hdr.a_text);
  350.     long new_mcaloff = MODCAL_OFFSET (new_hdr);
  351.     long old_mcaloff = MODCAL_OFFSET (old_hdr);
  352.     long newtext_size = new_hdr.a_text - old_dataddr;
  353.     long newdata1_size = (unsigned long)dynamic_beg - new_dataddr;
  354.     long dyn_size = (EXEC_ALIGN (old_hdr.a_text) + old_hdr.a_data)
  355.         - (unsigned long)dynamic_beg;
  356.     long newdata2_size = (unsigned long)current_break
  357.         - ((unsigned long)dynamic_beg + dyn_size);
  358.     long pad_size = 
  359.       MASK_UP (current_break, n_pagsiz) - ((unsigned long) current_break);
  360.  
  361. #ifdef DEBUG
  362.     printf ("current break is %#lx\n", current_break);
  363.  
  364.     printf ("old_dataddr = %#lx, dynamic_beg = %#lx\n",
  365.             old_dataddr, dynamic_beg);
  366. #endif
  367.  
  368.     /*
  369.      * First, write the text segment with new header -- copy
  370.      * everything until the start of the data segment from the old
  371.      * file
  372.      */
  373. #ifdef DEBUG
  374.     printf ("copying %#lx bytes of text from 0\n", old_datoff);
  375. #endif
  376.     unexec_copy (new_fd, old_fd, 0, 0, old_datoff);
  377.     /* pad out the text segment */
  378. #ifdef DEBUG
  379.     printf ( "text pad size is %#x\n", old_dataddr - old_hdr.a_text);
  380. #endif
  381.     unexec_pad (new_fd, old_dataddr - old_hdr.a_text);
  382.  
  383.     /*
  384.      * go back and write the new header.
  385.      */
  386.     unexec_write (new_fd, 0, (char *) &new_hdr, sizeof (new_hdr));
  387.  
  388.     
  389.     /*
  390.      * Copy the part of the data segment which becomes text from the
  391.      * running image.
  392.      */
  393. #ifdef DEBUG
  394.     printf ("copying %#lx bytes of new text from %#lx to position %#lx\n",
  395.             newtext_size, old_dataddr, TEXT_OFFSET(new_hdr) + old_dataddr);
  396. #endif
  397.     unexec_write (new_fd, TEXT_OFFSET(new_hdr) + old_dataddr,
  398.                   (caddr_t)old_dataddr, newtext_size);
  399.  
  400. #ifdef DEBUG
  401.     printf ("new DATA_OFFSET is %#lx\n", new_datoff);
  402. #endif
  403.  
  404.     /*
  405.      * Copy the part of the old data segment which will be data
  406.      * in the new executable (before the dynamic stuff)
  407.      * from the running image.
  408.      */
  409. #ifdef DEBUG
  410.     printf ("copying %#lx bytes of data from %#lx to position %#lx\n",
  411.             newdata1_size, new_dataddr, new_datoff);
  412. #endif
  413.     unexec_write (new_fd, new_datoff, (caddr_t)new_dataddr, newdata1_size);
  414.  
  415.     /* copy the dynamic part of the data segment from the old executable */
  416.     if (dyn_size)
  417.       {
  418. #ifdef DEBUG
  419.         printf ("copying %#lx bytes of dyn data from executable"
  420.                 " at address %#lx to position %#lx\n", 
  421.                 dyn_size, dynamic_beg, new_datoff + newdata1_size);
  422. #endif
  423.         unexec_copy (new_fd, old_fd, old_datoff + newtext_size + newdata1_size,
  424.                      new_datoff + newdata1_size, dyn_size);
  425.       }
  426.  
  427.     /* copy remaining data (old bss) from the running image */
  428. #ifdef DEBUG
  429.     printf ("copying %#lx bytes of data from %#lx to position %#lx\n",
  430.             newdata2_size, new_dataddr + newdata1_size + dyn_size,
  431.             new_datoff + newdata1_size + dyn_size);
  432. #endif
  433.     unexec_write (new_fd, new_datoff + newdata1_size + dyn_size,
  434.                   (caddr_t)(new_dataddr + newdata1_size + dyn_size),
  435.                   newdata2_size);
  436.  
  437.     /* pad out the data segment */
  438. #ifdef DEBUG
  439.     printf ( "pad size is %#x\n", pad_size);
  440. #endif
  441.     unexec_pad (new_fd, pad_size);
  442.     
  443.     /* Finally, copy the rest of the junk from the old file. */
  444. #ifdef DEBUG
  445.     printf ("Copying %#lx bytes of junk from %#lx (old) to %#lx (new)\n",
  446.             old_buf.st_size - old_mcaloff, old_mcaloff, new_mcaloff);
  447. #endif
  448.     unexec_copy (new_fd, old_fd, old_mcaloff, new_mcaloff,
  449.                  old_buf.st_size - old_mcaloff);
  450.   }
  451.      
  452.      
  453.   /* make the output file executable -- then quit */
  454.   unexec_fchmod (new_fd, 0755);
  455.   close (old_fd);
  456.   close (new_fd);
  457.   return 0;
  458. }
  459.  
  460.  
  461. int
  462. run_time_remap (char *dummy)
  463. {
  464.     unsigned long current_sbrk = (unsigned long) sbrk (0);
  465.  
  466.     if (sbrk_of_0_at_unexec < current_sbrk)
  467.         fprintf (stderr, "Absurd new brk addr = 0x%x (current = 0x%x)\n", 
  468.                  sbrk_of_0_at_unexec, current_sbrk);
  469.     else
  470.     {
  471.         errno = 0;
  472.         if (brk ((caddr_t) sbrk_of_0_at_unexec))
  473.             fprintf (stderr, "failed to change brk addr to 0x%x: %s\n", 
  474.                      sbrk_of_0_at_unexec, SYS_ERR);
  475.     }
  476.     
  477.   return 0;
  478. }
  479.